/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedLineData, pickedVertexData } from '@amcax/base';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { MessageTip } from '@app-cad/common/utils/MessageTip';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { previewer } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { FeatureBaseCommand, FeaturedCmdDialogParams } from '@app-cad/types';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useMemo, useState } from 'react';

enum InputMode {
  PICK = 'pick',
  COORDINATE = 'coordinate',
}

type FormData = {
  radius1: number;
  radius2: number;
  inputMode: InputMode;
  origin?: pickedVertexData;
  x?: number;
  y?: number;
  z?: number;
  zdir: pickedLineData;
};

type Params = {
  radius1: number;
  radius2: number;
  angle1: number;
  angle2: number;
  angle3: number;
  frame?: string | Array<number>;
  postype: string;
  origin: string | Array<number>;
  zdir: string;
};

// 圆环（甜甜圈）
function Torus({ title, onClose, props }: FeaturedCmdDialogParams) {
  const initData: FormData = {
    radius1: 100,
    radius2: 20,
    inputMode: InputMode.PICK,
    origin: null,
    x: 0,
    y: 0,
    z: 0,
    zdir: null,
  };
  const [formData, setFormData] = useState<FormData>(initData);

  const { picker } = useTools();

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const params: Params = props.params;
    const { radius1, radius2, origin, zdir } = params;

    await initEditDependency([Array.isArray(origin) ? null : origin, zdir]);

    let datas = {} as FormData;
    if (Array.isArray(origin)) {
      const ori = origin as Array<number>;
      datas = {
        radius1: radius1,
        radius2: radius2,
        inputMode: InputMode.COORDINATE,
        x: ori[0],
        y: ori[1],
        z: ori[2],
        zdir: picker.generatePickObjByPickID(zdir) as pickedLineData,
      };
    } else {
      datas = {
        radius1: radius1,
        radius2: radius2,
        inputMode: InputMode.PICK,
        origin: picker.generatePickObjByPickID(
          origin as string,
        ) as pickedVertexData,
        zdir: picker.generatePickObjByPickID(zdir) as pickedLineData,
      };
    }

    setFormData(datas);
  }, []);

  useAsyncEffect(async () => {
    preview();
  }, [formData]);

  const preview = async () => {
    if (!isFormDataValid()) {
      previewer.clear();
      return;
    }
    await execute(true);
  };

  const isFormDataValid = () => {
    const { radius1, radius2, origin, zdir, inputMode, x, y, z } = formData;
    if (radius1 === radius2) {
      MessageTip.warning('外圆半径与截面半径不能相等');
      return false;
    }
    if (inputMode === InputMode.PICK) {
      return (
        radius1 !== null && radius2 !== null && origin !== null && zdir !== null
      );
    } else {
      return (
        radius1 !== null &&
        radius2 !== null &&
        x !== null &&
        y !== null &&
        z !== null &&
        zdir !== null
      );
    }
  };
  const finishValid = useMemo(isFormDataValid, [formData]);
  const checkAndFinish = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);

    onClose();
  };

  const { initEditDependency, isPreviewLoading, previewInCommand } = useCommand(
    'cmd-torus',
    {
      onClose,
      finishDraw: checkAndFinish,
    },
  );

  const execute = async (preview: boolean = false) => {
    const { radius1, radius2, origin, zdir, x, y, z, inputMode } = formData;
    let originObj;
    if (inputMode === InputMode.PICK) {
      originObj = getIdOfPickedObj(origin);
    } else {
      originObj = [x, y, z];
    }
    const zID = getIdOfPickedObj(zdir);
    const params: Params = {
      radius1: radius1,
      radius2: radius2,
      angle1: -180,
      angle2: 180,
      angle3: 360,
      postype: 'center',
      origin: originObj,
      zdir: zID,
    };
    const res =
      props == null
        ? await wsApi.createPrimitiveNew('Torus', params, preview)
        : await wsApi.setParams((props as any).shape, params, preview);

    if (preview) {
      await previewInCommand(res);
    }

    return res;
  };

  const schema = useMemo(() => {
    const modeSchema = {
      type: 'string',
      title: '中心点输入方式',
      default: InputMode.PICK,
      oneOf: [
        {
          type: 'string',
          title: '拾取点',
          const: InputMode.PICK,
        },
        {
          type: 'string',
          title: '点坐标',
          const: InputMode.COORDINATE,
        },
      ],
    };

    // 拾取
    if (formData.inputMode === InputMode.PICK) {
      return {
        properties: {
          inputMode: modeSchema,
          origin: {
            type: 'string',
            format: PickInputRJSFFormat.PickVertex,
          },
          zdir: {
            type: 'string',
            format: PickInputRJSFFormat.PickDirection,
          },
          radius1: {
            type: 'number',
            title: '外圆半径',
            dafault: 100,
            format: NumberInputFormat.Length,
          },
          radius2: {
            type: 'number',
            title: '截面半径',
            dafault: 20,
            format: NumberInputFormat.Length,
          },
        },
      };
    }

    // 坐标值
    if (formData.inputMode === InputMode.COORDINATE) {
      return {
        properties: {
          inputMode: modeSchema,
          x: {
            type: 'number',
            title: 'x',
            dafault: 0,
            format: NumberInputFormat.Length,
          },
          y: {
            type: 'number',
            title: 'y',
            dafault: 0,
            format: NumberInputFormat.Length,
          },
          z: {
            type: 'number',
            title: 'z',
            dafault: 0,
            format: NumberInputFormat.Length,
          },
          zdir: {
            type: 'string',
            format: PickInputRJSFFormat.PickDirection,
          },
          radius1: {
            type: 'number',
            title: '外圆半径',
            dafault: 100,
            format: NumberInputFormat.Length,
          },
          radius2: {
            type: 'number',
            title: '截面半径',
            dafault: 20,
            format: NumberInputFormat.Length,
          },
        },
      };
    }

    return schema;
  }, [formData.inputMode]);

  return (
    <PickableCommandForm
      isFormDataValid={finishValid}
      disabled={false}
      onClose={onClose}
      title={title}
      schema={schema}
      formData={formData}
      previewLoading={isPreviewLoading}
      onChange={(v) => {
        setFormData(v);
      }}
      extraUiSchema={{
        origin: {
          'ui:placeholder': '中心',
          'ui:autofocus': true,
        },
        zdir: {
          'ui:placeholder': '方向',
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinish}
    />
  );
}

export const cmdTorus: FeatureBaseCommand = {
  id: 'CmdTorus',
  label: 'command.torus',
  icon: 'commands/feature/torus',
  create: (label, onClose, props) => (
    <Torus
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
